package com.maozzi.api.auth;

import com.alibaba.fastjson.JSON;
import com.maozzi.api.auth.anotation.RequirePermissions;
import com.maozzi.api.auth.constant.AuthConstant;
import com.maozzi.api.auth.enums.UserTypeEnum;
import com.maozzi.api.auth.model.UserInfo;
import com.maozzi.api.auth.properties.AuthProperties;
import com.maozzi.common.constant.ErrorCodeConstant;
import com.maozzi.common.exception.BizException;
import com.maozzi.common.model.ResultVO;
import com.maozzi.common.util.AesUtil;
import com.maozzi.common.util.HttpUtil;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 权限拦截器
 *
 * @author maozi
 */
public class AuthInterceptor implements HandlerInterceptor {

    /**
     * 请求头认证参数
     */
    private final String authCookie;

    /**
     * 主机
     */
    private final String host;

    /**
     * 查询用户信息URL
     */
    private final String userInfoUrl;

    /**
     * 查询acl用户信息URL
     */
    private final String aclUserInfoUrl;

    public AuthInterceptor(AuthProperties authProperties) {
        this.authCookie = authProperties.getAuthCookie();
        this.host = authProperties.getHost();
        this.userInfoUrl = authProperties.getUserInfoUrl();
        this.aclUserInfoUrl = authProperties.getAclUserInfoUrl();
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String url = request.getRequestURI();
        if (AuthConstant.ERROR_URL.equalsIgnoreCase(url)
                || userInfoUrl.equalsIgnoreCase(url) || aclUserInfoUrl.equalsIgnoreCase(url)) {
            return true;
        }
        String token = getToken(request);
        if (StringUtils.isEmpty(token)) {
            // 未登录
            throw new BizException(ErrorCodeConstant.NEED_LOGIN, "您好，请先登录");
        }
        Boolean hasPermission = checkUserHasPermission(token, handler);
        if (!hasPermission) {
            throw new BizException(ErrorCodeConstant.FORBIDDEN, "无权限禁止访问");
        }
        return true;
    }

    /**
     * 获取cookie token
     *
     * @param request 请求
     * @return 返回
     */
    private String getToken(HttpServletRequest request) {
        String token = null;
        for (Cookie cookie : request.getCookies()) {
            String name = cookie.getName();
            if (authCookie.equalsIgnoreCase(name)) {
                token = cookie.getValue();
                break;
            }
        }
        return token;
    }

    /**
     * 检查用户是否拥有权限
     *
     * @param token 用户token
     * @return false - 无权限
     */
    private Boolean checkUserHasPermission(String token, Object handler) {
        RequirePermissions annotation = null;
        // 如果是SpringMVC请求
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            annotation = handlerMethod.getMethodAnnotation(RequirePermissions.class);
        }
        if (ObjectUtils.isEmpty(annotation)) {
            annotation = handler.getClass().getAnnotation(RequirePermissions.class);
        }

        // 发送请求
        Map<String, String> headers = new HashMap<>(1);
        headers.put("X-Requested-With", "XMLHttpRequest");
        Map<String, String> params = new HashMap<>(3);
        String timestamp = String.valueOf(System.currentTimeMillis());
        params.put("timestamp", timestamp);
        params.put("sign", AesUtil.encrypt(token, timestamp));
        params.put("token", token);
        String response = HttpUtil.sendGet(host + aclUserInfoUrl, headers, params);
        ResultVO<UserInfo> resultVO = JSON.parseObject(response, ResultVO.class);
        if (ObjectUtils.isEmpty(resultVO) || ObjectUtils.isEmpty(resultVO.getData())) {
            return Boolean.FALSE;
        }

        UserInfo userInfo = JSON.parseObject(JSON.toJSONString(resultVO.getData()), UserInfo.class);

        // 检查用户类型
        UserTypeEnum type = userInfo.getType();
        if (UserTypeEnum.NORMAL.equals(type)) {
            return Boolean.FALSE;
        }
        if (UserTypeEnum.SUPER_ADMIN.equals(type)) {
            return Boolean.TRUE;
        }

        // 检查角色
        String[] roles = annotation.role();
        List<String> roleList = userInfo.getRoles();
        if (!ObjectUtils.isEmpty(roles) && !ObjectUtils.isEmpty(roleList)) {
            List<String> list = Arrays.stream(roles).filter(roleList::contains).collect(Collectors.toList());
            return ObjectUtils.isEmpty(list) ? Boolean.FALSE : Boolean.TRUE;
        }

        // 检查权限码
        String[] codes = annotation.code();
        List<String> permissions = userInfo.getPermissions();
        if (!ObjectUtils.isEmpty(codes) && !ObjectUtils.isEmpty(permissions)) {
            List<String> list = Arrays.stream(codes).filter(permissions::contains).collect(Collectors.toList());
            return ObjectUtils.isEmpty(list) ? Boolean.FALSE : Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

}
